package com.xoa.util.nccloudApi;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.lang3.StringUtils;
import com.google.gson.Gson;
import com.xoa.util.workapi.CompressUtil;
import com.xoa.util.workapi.Decryption;
import com.xoa.util.workapi.Encryption;
import com.xoa.util.workapi.ResultMessageUtil;
import com.xoa.util.workapi.SHA256Util;
import org.springframework.beans.factory.annotation.Value;

/**
 * 1.从resources/config.properties中读取测试api相关的数据 2.运行程序，测试查看测试结果
 *
 * @author wmf
 * @date 2021年5月19日上午10:53:11
 */
public class NcCloudAPI {

    // app_secret
    private static String client_secret = null;
    // 公钥
    private static String pubKey = null;
    // app_id
    private static String client_id = null;
    // ncc用户名
    private static String username = null;
    // ncc用户名密码
    private static String pwd = null;
    // ncc账套
    private static String busi_center = null;
    // 获取token方式：client_credentials、password
    private static String grant_type = null;
    // 服务器ip：port
    private static String baseUrl = null;
    // 返回值压缩加密级别
    private static String secret_level = null;
    // 请求参数
    private static String requestBody = null;
    // openapi请求路径
    private static String apiUrl = null;

    // 访问api获取到的access_token
    public static String token = null;
    // 重复调用检查
    public static String repeat_check = null;
    // 接口调用业务标识
    public static String busi_id = null;

    /**
     * 启动入口
     *
     * @param args
     */
    public static void main(String[] args) {
        try {
            // 初始化数据
            init();
            // 请求token
            token = getToken();
            System.out.println("getTokenData:" + token);
            if (token != null) {
                // 测试openapi
                testApi(token);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取access_token
     *
     * @return
     * @throws Exception
     */
    private static String getToken() throws Exception {
        String token = null;
        if ("password".equals(grant_type)) {
            // 密码模式
            token = getTokenByPWD();
        } else if ("client_credentials".equals(grant_type)) {
            // 客户端模式
            token = getTokenByClient();
        }
        return token;
    }

    /**
     * 客户端模式获取token
     *
     * @return
     * @throws Exception
     */
    private static String getTokenByClient() throws Exception {
        Map<String, String> paramMap = new HashMap<String, String>();
        // 密码模式认证
        paramMap.put("grant_type", "client_credentials");
        // 第三方应用id
        paramMap.put("client_id", client_id);
        // 第三方应用secret 公钥加密
        paramMap.put("client_secret", URLEncoder.encode(
                Encryption.pubEncrypt(pubKey, client_secret), "utf-8"));
        // 账套编码
        paramMap.put("biz_center", busi_center);
        // // TODO 传递数据源和ncc登录用户
        // paramMap.put("dsname", "TM_0614");
        // paramMap.put("usercode", "1");

        // 签名
        String sign = SHA256Util.getSHA256(client_id + client_secret + pubKey);
        paramMap.put("signature", sign);

        String url = baseUrl + "/nccloud/opm/accesstoken";
        String mediaType = "application/x-www-form-urlencoded";
        String token = doPost(url, paramMap, mediaType, null, "");
        return token;
    }

    /**
     * 密码模式获取token
     *
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unused")
    private static String getTokenByPWD() throws Exception {
        Map<String, String> paramMap = new HashMap<String, String>();
        // 密码模式认证
        paramMap.put("grant_type", "password");
        // 第三方应用id
        paramMap.put("client_id", client_id);
        // 第三方应用secret 公钥加密
        paramMap.put("client_secret", URLEncoder.encode(
                Encryption.pubEncrypt(pubKey, client_secret), "utf-8"));
        // ncc用户名
        paramMap.put("username", username);
        // 密码 公钥加密
        paramMap.put("password",
                URLEncoder.encode(Encryption.pubEncrypt(pubKey, pwd), "utf-8"));
        // 账套编码
        paramMap.put("biz_center", busi_center);
        // 签名
        String sign = SHA256Util.getSHA256(client_id + client_secret + username
                + pwd + pubKey);
        paramMap.put("signature", sign);

        String url = baseUrl + "/nccloud/opm/accesstoken";
        String mediaType = "application/x-www-form-urlencoded";
        String token = doPost(url, paramMap, mediaType, null, "");
        return token;
    }

    /**
     * 请求openapi
     *
     * @param token
     *
     * @throws Exception
     */
    private static void testApi(String token) throws Exception {
        // token转对象，获取api访问所用token和secret
        ResultMessageUtil returnData = new Gson().fromJson(token,
                ResultMessageUtil.class);
        Map<String, String> data = (Map<String, String>) returnData.getData();
        String access_token = data.get("access_token");
        String security_key = data.get("security_key");
//		String refresh_token = data.get("refresh_token");
        System.out.println("【ACCESS_TOKEN】:" + access_token);

        // 请求路径
        String url = baseUrl + apiUrl;
        // header 参数
        Map<String, String> headermap = new HashMap<>();
        headermap.put("access_token", access_token);
        headermap.put("client_id", client_id);

        StringBuffer sb = new StringBuffer();
        sb.append(client_id);
        if (StringUtils.isNotBlank(requestBody)) {
            // sb.append(requestBody.replaceAll("\\s*|\t|\r|\n", "").trim());
            sb.append(requestBody);
        }
        sb.append(pubKey);
        String sign = SHA256Util.getSHA256(sb.toString());
        headermap.put("signature", sign);

        if (StringUtils.isNotBlank(busi_id)) {
            headermap.put("busi_id", busi_id);
        }
        if (StringUtils.isNotBlank(repeat_check)) {
            headermap.put("repeat_check", repeat_check);
        }
        headermap.put("ucg_flag", "y");

        String mediaType = "application/json;charset=utf-8";

        // 表体数据json
        // 根据安全级别选择加密或压缩请求表体参数
        String json = dealRequestBody(requestBody, security_key, secret_level);

        // 返回值
        String result = doPost(url, null, mediaType, headermap, json);
        System.out.println("【RESULT】:" + result);
        String result2DecryptAndDecompress = dealResponseBody(result,
                security_key, secret_level);

        System.out.println("result解密:" + result2DecryptAndDecompress);
    }

    /**
     * 返回值进行过加密和压缩，对返回值进行解压和解密
     *
     * @param source
     * @param security_key
     * @param level
     * @return
     * @throws Exception
     */
    private static String dealResponseBody(String source, String security_key,
                                           String level) throws Exception {
        String result = null;

        if (StringUtils.isEmpty(level) || SecretConst.LEVEL0.equals(level)) {
            result = source;
        } else if (SecretConst.LEVEL1.equals(level)) {
            result = Decryption.symDecrypt(security_key, source);
        } else if (SecretConst.LEVEL2.equals(level)) {
            result = CompressUtil.gzipDecompress(source);
        } else if (SecretConst.LEVEL3.equals(level)) {
            result = CompressUtil.gzipDecompress(Decryption.symDecrypt(
                    security_key, source));
        } else if (SecretConst.LEVEL4.equals(level)) {
            result = Decryption.symDecrypt(security_key,
                    CompressUtil.gzipDecompress(source));
        } else {
            throw new Exception("无效的安全等级");
        }

        return result;
    }

    /**
     * 初始化参数
     */
    private static void init() {
        // TODO Auto-generated method stub
        Properties properties = new Properties();

        String filepath = "/resources/config/properties/workapiconfig.properties";
        ClassLoader classloader = Thread.currentThread()
                .getContextClassLoader();
//        InputStream inputStream = classloader.getResourceAsStream(filepath);
        try {
//            InputStreamReader reader = new InputStreamReader(inputStream,"UTF-8");
//            System.out.println(NcCloudAPI.class.getClassLoader().getResource(""));
            properties.load(NcCloudAPI.class.getClassLoader()
                    .getResourceAsStream( "../resources/config/properties/workapiconfig.properties"));
//            properties.load(reader);

            client_secret = new String(properties.getProperty("client_secret")
                    .getBytes("utf-8"), "utf-8");
            client_id = properties.getProperty("client_id");
            pubKey = properties.getProperty("pubKey");
            username = properties.getProperty("username");
            pwd = properties.getProperty("pwd");
            busi_center = properties.getProperty("busi_center");
            baseUrl = properties.getProperty("baseUrl");
            requestBody = new String(properties.getProperty("requestBody")
                    .getBytes("utf-8"), "utf-8");
            apiUrl = properties.getProperty("apiUrl");
            grant_type = properties.getProperty("grant_type");
            secret_level = properties.getProperty("secret_level");
            repeat_check = properties.getProperty("repeat_check");
            busi_id = properties.getProperty("busi_id");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    // 根据安全级别设置，表体是否加密或压缩
    private static String dealRequestBody(String source, String security_key,
                                          String level) throws Exception {
        String result = null;
        if (StringUtils.isEmpty(level) || SecretConst.LEVEL0.equals(level)) {
            result = source;
        } else if (SecretConst.LEVEL1.equals(level)) {
            result = Encryption.symEncrypt(security_key, source);
        } else if (SecretConst.LEVEL2.equals(level)) {
            result = CompressUtil.gzipCompress(source);
        } else if (SecretConst.LEVEL3.equals(level)) {
            result = Encryption.symEncrypt(security_key,
                    CompressUtil.gzipCompress(source));
        } else if (SecretConst.LEVEL4.equals(level)) {
            result = CompressUtil.gzipCompress(Encryption.symEncrypt(
                    security_key, source));
        } else {
            throw new Exception("无效的安全等级");
        }

        return result;
    }

    /**
     * 发送post请求
     *
     * @param baseUrl
     * @param paramMap
     * @param mediaType
     * @param headers
     * @param json
     * @return
     */
    private static String doPost(String baseUrl, Map<String, String> paramMap,
                                 String mediaType, Map<String, String> headers, String json) {

        HttpURLConnection urlConnection = null;
        InputStream in = null;
        OutputStream out = null;
        BufferedReader bufferedReader = null;
        String result = null;
        try {
            StringBuffer sb = new StringBuffer();
            sb.append(baseUrl);
            if (paramMap != null) {
                sb.append("?");
                for (Map.Entry<String, String> entry : paramMap.entrySet()) {
                    String key = entry.getKey();
                    String value = entry.getValue();
                    sb.append(key + "=" + value).append("&");
                }
                baseUrl = sb.toString()
                        .substring(0, sb.toString().length() - 1);
            }

            URL urlObj = new URL(baseUrl);
            urlConnection = (HttpURLConnection) urlObj.openConnection();
            urlConnection.setConnectTimeout(50000);
            urlConnection.setRequestMethod("POST");
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            urlConnection.setUseCaches(false);
            urlConnection.addRequestProperty("content-type", mediaType);
            if (headers != null) {
                for (String key : headers.keySet()) {
                    urlConnection.addRequestProperty(key, headers.get(key));
                }
            }
            out = urlConnection.getOutputStream();
            out.write(json.getBytes("utf-8"));
            out.flush();
            int resCode = urlConnection.getResponseCode();
            if (resCode == HttpURLConnection.HTTP_OK
                    || resCode == HttpURLConnection.HTTP_CREATED
                    || resCode == HttpURLConnection.HTTP_ACCEPTED) {
                in = urlConnection.getInputStream();
            } else {
                in = urlConnection.getErrorStream();
            }
            bufferedReader = new BufferedReader(new InputStreamReader(in,
                    "utf-8"));
            StringBuffer temp = new StringBuffer();
            String line = bufferedReader.readLine();
            while (line != null) {
                temp.append(line).append("\r\n");
                line = bufferedReader.readLine();
            }
            String ecod = urlConnection.getContentEncoding();
            if (ecod == null) {
                ecod = Charset.forName("utf-8").name();
            }
            result = new String(temp.toString().getBytes("utf-8"), ecod);
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            if (null != bufferedReader) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != out) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != in) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            urlConnection.disconnect();
        }
        return result;
    }

    class SecretConst {
        /**
         * LEVEL0 不压缩、不加密
         */
        public static final String LEVEL0 = "L0";
        /**
         * LEVEL1 只加密、不压缩
         */
        public static final String LEVEL1 = "L1";
        /**
         * LEVEL2 只压缩、不加密
         */
        public static final String LEVEL2 = "L2";
        /**
         * LEVEL3 先压缩、后加密
         */
        public static final String LEVEL3 = "L3";
        /**
         * LEVEL4 先加密、后压缩
         */
        public static final String LEVEL4 = "L4";
    }

}
